# ============================================================================
# 编译性能优化模块
# ============================================================================
# 提供编译性能优化的辅助函数和配置
# ============================================================================

# 函数：优化的源文件收集（替代 AUX_SOURCE_DIRECTORY）
# 使用 GLOB_RECURSE 但提供更好的依赖跟踪
function(optimized_collect_sources VAR_NAME DIR)
    # 使用 GLOB 收集源文件（比 AUX_SOURCE_DIRECTORY 更高效）
    file(GLOB_RECURSE ${VAR_NAME}
        "${DIR}/*.cpp"
        "${DIR}/*.c"
        "${DIR}/*.cc"
        "${DIR}/*.cxx"
    )
    
    # 排除不需要的文件（如测试文件、示例文件等）
    if(${VAR_NAME})
        list(FILTER ${VAR_NAME} EXCLUDE REGEX ".*[Tt]est.*\\.(cpp|c|cc|cxx)$")
        list(FILTER ${VAR_NAME} EXCLUDE REGEX ".*[Ee]xample.*\\.(cpp|c|cc|cxx)$")
        list(FILTER ${VAR_NAME} EXCLUDE REGEX ".*[Mm]ain\\.(cpp|c|cc|cxx)$")
    endif()
    
    # 设置父作用域变量
    set(${VAR_NAME} ${${VAR_NAME}} PARENT_SCOPE)
endfunction()

# 函数：为目标启用预编译头文件（PCH）
# 使用方式: enable_precompiled_headers(target_name "pch_header.h")
function(enable_precompiled_headers TARGET_NAME PCH_HEADER)
    if(MSVC)
        # MSVC 预编译头文件
        target_precompile_headers(${TARGET_NAME} PRIVATE ${PCH_HEADER})
        message(STATUS "✅ 为目标 ${TARGET_NAME} 启用预编译头文件: ${PCH_HEADER}")
    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
        # GCC/Clang 预编译头文件（需要 CMake 3.16+）
        if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.16")
            target_precompile_headers(${TARGET_NAME} PRIVATE ${PCH_HEADER})
            message(STATUS "✅ 为目标 ${TARGET_NAME} 启用预编译头文件: ${PCH_HEADER}")
        else()
            message(WARNING "预编译头文件需要 CMake 3.16+，当前版本: ${CMAKE_VERSION}")
        endif()
    endif()
endfunction()

# 函数：优化目标编译设置
function(optimize_target_compilation TARGET_NAME)
    # 1. 启用并行编译（如果支持）
    if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12")
        set_target_properties(${TARGET_NAME} PROPERTIES
            JOB_POOL_COMPILE compile_pool
            JOB_POOL_LINK link_pool
        )
    endif()
    
    # 2. 优化编译输出目录结构
    set_target_properties(${TARGET_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
        LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
    )
    
    # 3. 启用更激进的依赖优化（如果支持）
    if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
        set_target_properties(${TARGET_NAME} PROPERTIES
            UNITY_BUILD OFF  # 默认关闭 Unity Build（可能影响调试）
        )
    endif()
    
    message(STATUS "✅ 已优化目标 ${TARGET_NAME} 的编译设置")
endfunction()

# 函数：设置编译缓存优化
function(setup_compile_cache)
    # 如果使用 Ninja，优化依赖文件生成
    if(CMAKE_GENERATOR MATCHES "Ninja")
        # Ninja 使用 .d 文件跟踪依赖，比 /showIncludes 更高效
        set(CMAKE_NINJA_DEPTYPE_C "gcc" CACHE STRING "" FORCE)
        set(CMAKE_NINJA_DEPTYPE_CXX "gcc" CACHE STRING "" FORCE)
        message(STATUS "✅ 已优化 Ninja 依赖跟踪")
    endif()
endfunction()

# 函数：确保可执行文件依赖所有库目标（手动指定方式）
# 使用方式: ensure_link_dependencies(executable_target lib1 lib2 ...)
# 
# 注意：如果使用了 ensure_link_dependencies_from_target，通常不需要再调用此函数
# 此函数适用于以下场景：
# 1. 某些库没有在 TARGET_LINK_LIBRARIES 中列出，但仍需要依赖
# 2. 需要在链接之前就确保某些库已编译
# 3. 显式声明依赖关系，提高代码可读性
function(ensure_link_dependencies EXECUTABLE_TARGET)
    # 遍历所有参数（库目标名）
    foreach(lib_target ${ARGN})
        # 检查目标是否存在（CMake 目标）
        if(TARGET ${lib_target})
            # 使用 add_dependencies 确保库目标先编译
            add_dependencies(${EXECUTABLE_TARGET} ${lib_target})
            message(STATUS "✅ 已添加依赖: ${EXECUTABLE_TARGET} -> ${lib_target}")
        else()
            # 如果是库文件名（如 NFPluginManager.a），尝试查找对应的 CMake 目标
            # 移除 .a 后缀和 lib 前缀
            string(REGEX REPLACE "^lib" "" lib_name "${lib_target}")
            string(REGEX REPLACE "\\.a$" "" lib_name "${lib_name}")
            
            # 尝试查找对应的目标
            if(TARGET ${lib_name})
                add_dependencies(${EXECUTABLE_TARGET} ${lib_name})
                message(STATUS "✅ 已添加依赖: ${EXECUTABLE_TARGET} -> ${lib_name} (从 ${lib_target})")
            else()
                # 如果找不到目标，记录警告但不报错（可能是外部库）
                message(STATUS "⚠️  未找到目标: ${lib_target} (可能是外部库)")
            endif()
        endif()
    endforeach()
endfunction()

# 函数：智能链接库（自动建立依赖关系）
# 使用方式: smart_target_link_libraries(target_name [PRIVATE|PUBLIC|INTERFACE] lib1 lib2 ...)
# 这个函数会调用 TARGET_LINK_LIBRARIES，并自动从库列表中提取库名建立依赖关系
function(smart_target_link_libraries TARGET_NAME)
    # 调用原始的 TARGET_LINK_LIBRARIES
    target_link_libraries(${TARGET_NAME} ${ARGN})
    
    # 从参数中提取库名并建立依赖关系
    foreach(lib ${ARGN})
        # 跳过关键字（PRIVATE, PUBLIC, INTERFACE）
        if(NOT lib STREQUAL "PRIVATE" AND NOT lib STREQUAL "PUBLIC" AND NOT lib STREQUAL "INTERFACE")
            # 跳过系统库和链接选项（以 - 开头或以 $< 开头的生成器表达式）
            if(NOT lib MATCHES "^-" AND NOT lib MATCHES "^\\$<")
                # 处理库文件名（如 NFPluginManager.a, libNFPluginManager.a）
                set(lib_name "${lib}")
                
                # 移除路径前缀（如果有）
                get_filename_component(lib_name ${lib_name} NAME_WE)
                
                # 移除 lib 前缀（如果有）
                string(REGEX REPLACE "^lib" "" lib_name "${lib_name}")
                
                # 移除 .a 后缀（如果有）
                string(REGEX REPLACE "\\.a$" "" lib_name "${lib_name}")
                
                # 检查是否是 CMake 目标
                if(TARGET ${lib_name})
                    add_dependencies(${TARGET_NAME} ${lib_name})
                    message(STATUS "✅ 已从链接库自动添加依赖: ${TARGET_NAME} -> ${lib_name} (从 ${lib})")
                endif()
            endif()
        endif()
    endforeach()
endfunction()

# 宏：智能链接库（自动建立依赖关系）
# 使用方式: smart_target_link_libraries(executable_target lib1 lib2 ...)
# 这个宏会先建立依赖关系，然后调用 TARGET_LINK_LIBRARIES
# 推荐使用此宏替代 TARGET_LINK_LIBRARIES，避免重复列出库名
macro(smart_target_link_libraries_macro TARGET_NAME)
    # 先建立依赖关系
    ensure_link_dependencies_from_libs(${TARGET_NAME} ${ARGN})
    # 然后链接库
    target_link_libraries(${TARGET_NAME} ${ARGN})
endmacro()

# 函数：从链接库参数中提取库名并建立依赖关系（在 TARGET_LINK_LIBRARIES 之前调用）
# 使用方式: ensure_link_dependencies_from_libs(executable_target lib1 lib2 ...)
# 然后调用: TARGET_LINK_LIBRARIES(executable_target lib1 lib2 ...)
function(ensure_link_dependencies_from_libs EXECUTABLE_TARGET)
    foreach(lib ${ARGN})
        # 跳过系统库和链接选项（以 - 开头或以 $< 开头的生成器表达式）
        if(NOT lib MATCHES "^-" AND NOT lib MATCHES "^\\$<")
            # 处理库文件名（如 NFPluginManager.a, libNFPluginManager.a, NFPluginManager）
            set(lib_name "${lib}")
            
            # 移除路径前缀（如果有）
            get_filename_component(lib_name ${lib_name} NAME_WE)
            
            # 移除 lib 前缀（如果有）
            string(REGEX REPLACE "^lib" "" lib_name "${lib_name}")
            
            # 移除 .a 后缀（如果有）
            string(REGEX REPLACE "\\.a$" "" lib_name "${lib_name}")
            
            # 检查是否是 CMake 目标
            if(TARGET ${lib_name})
                add_dependencies(${EXECUTABLE_TARGET} ${lib_name})
                message(STATUS "✅ 已从链接库参数添加依赖: ${EXECUTABLE_TARGET} -> ${lib_name} (从 ${lib})")
            endif()
        endif()
    endforeach()
endfunction()

# 函数：从 TARGET_LINK_LIBRARIES 自动提取库名并建立依赖关系
# 使用方式: 在 TARGET_LINK_LIBRARIES 之后调用 ensure_link_dependencies_from_target(executable_target)
# 注意：此函数可能无法获取所有链接库（因为 CMake 内部格式转换），推荐使用 ensure_link_dependencies_from_libs
function(ensure_link_dependencies_from_target EXECUTABLE_TARGET)
    # 获取目标的链接库列表
    get_target_property(link_libs ${EXECUTABLE_TARGET} LINK_LIBRARIES)
    
    if(link_libs)
        foreach(lib ${link_libs})
            # 跳过系统库和链接选项（以 - 开头或以 $< 开头的生成器表达式）
            if(NOT lib MATCHES "^-" AND NOT lib MATCHES "^\\$<")
                # 处理库文件名（如 NFPluginManager.a, libNFPluginManager.a）
                set(lib_name "${lib}")
                
                # 移除路径前缀（如果有）
                get_filename_component(lib_name ${lib_name} NAME_WE)
                
                # 移除 lib 前缀（如果有）
                string(REGEX REPLACE "^lib" "" lib_name "${lib_name}")
                
                # 移除 .a 后缀（如果有）
                string(REGEX REPLACE "\\.a$" "" lib_name "${lib_name}")
                
                # 检查是否是 CMake 目标
                if(TARGET ${lib_name})
                    add_dependencies(${EXECUTABLE_TARGET} ${lib_name})
                    message(STATUS "✅ 已从链接库自动添加依赖: ${EXECUTABLE_TARGET} -> ${lib_name} (从 ${lib})")
                endif()
            endif()
        endforeach()
    endif()
    
    # 同时检查 INTERFACE_LINK_LIBRARIES（如果存在）
    get_target_property(interface_libs ${EXECUTABLE_TARGET} INTERFACE_LINK_LIBRARIES)
    if(interface_libs)
        foreach(lib ${interface_libs})
            if(NOT lib MATCHES "^-" AND NOT lib MATCHES "^\\$<")
                set(lib_name "${lib}")
                get_filename_component(lib_name ${lib_name} NAME_WE)
                string(REGEX REPLACE "^lib" "" lib_name "${lib_name}")
                string(REGEX REPLACE "\\.a$" "" lib_name "${lib_name}")
                
                if(TARGET ${lib_name})
                    add_dependencies(${EXECUTABLE_TARGET} ${lib_name})
                    message(STATUS "✅ 已从接口链接库自动添加依赖: ${EXECUTABLE_TARGET} -> ${lib_name} (从 ${lib})")
                endif()
            endif()
        endforeach()
    endif()
endfunction()

# 函数：为可执行文件设置链接依赖（确保所有库先编译）
# 这个函数会解析 TARGET_LINK_LIBRARIES 中的库，并建立依赖关系
function(setup_executable_link_dependencies EXECUTABLE_TARGET)
    # 获取目标的链接库列表
    get_target_property(link_libs ${EXECUTABLE_TARGET} LINK_LIBRARIES)
    if(link_libs)
        # 遍历链接库，建立依赖关系
        foreach(lib ${link_libs})
            # 跳过系统库和链接选项（以 - 开头）
            if(NOT lib MATCHES "^-")
                # 移除可能的路径前缀
                get_filename_component(lib_name ${lib} NAME_WE)
                # 移除 lib 前缀
                string(REGEX REPLACE "^lib" "" lib_name "${lib_name}")
                
                # 检查是否是 CMake 目标
                if(TARGET ${lib_name})
                    add_dependencies(${EXECUTABLE_TARGET} ${lib_name})
                endif()
            endif()
        endforeach()
    endif()
endfunction()

# 函数：创建库目标（统一接口）
# 使用方式: create_library_target(target_name [STATIC|SHARED] [sources...])
function(create_library_target TARGET_NAME)
    set(LIB_TYPE STATIC)
    set(SOURCES "")
    
    # 解析参数
    foreach(arg ${ARGN})
        if(arg STREQUAL "STATIC" OR arg STREQUAL "SHARED")
            set(LIB_TYPE ${arg})
        else()
            list(APPEND SOURCES ${arg})
        endif()
    endforeach()
    
    # 创建库
    add_library(${TARGET_NAME} ${LIB_TYPE} ${SOURCES})
    
    # 应用优化设置
    optimize_target_compilation(${TARGET_NAME})
    
    # 设置 PDB 文件名（Windows）
    if(WIN32 AND MSVC)
        set_target_pdb_name(${TARGET_NAME})
    endif()
endfunction()

# 函数：创建可执行文件目标（统一接口）
# 使用方式: create_executable_target(target_name [sources...])
function(create_executable_target TARGET_NAME)
    # 创建可执行文件
    add_executable(${TARGET_NAME} ${ARGN})
    
    # 应用优化设置
    optimize_target_compilation(${TARGET_NAME})
    
    # 设置 PDB 文件名（Windows）
    if(WIN32 AND MSVC)
        set_target_pdb_name(${TARGET_NAME})
    endif()
endfunction()

# 函数：收集源文件（改进版本，支持排除模式）
# 使用方式: collect_sources(VAR_NAME DIR [EXCLUDE pattern1 pattern2 ...])
function(collect_sources VAR_NAME DIR)
    # 收集所有源文件
    file(GLOB_RECURSE sources
        "${DIR}/*.cpp"
        "${DIR}/*.c"
        "${DIR}/*.cc"
        "${DIR}/*.cxx"
    )
    
    # 处理排除模式
    set(exclude_patterns "")
    set(collecting_excludes FALSE)
    
    foreach(arg ${ARGN})
        if(arg STREQUAL "EXCLUDE")
            set(collecting_excludes TRUE)
        elseif(collecting_excludes)
            list(APPEND exclude_patterns ${arg})
        endif()
    endforeach()
    
    # 应用排除模式
    if(exclude_patterns)
        foreach(pattern ${exclude_patterns})
            list(FILTER sources EXCLUDE REGEX "${pattern}")
        endforeach()
    else()
        # 默认排除测试和示例文件
        list(FILTER sources EXCLUDE REGEX ".*[Tt]est.*\\.(cpp|c|cc|cxx)$")
        list(FILTER sources EXCLUDE REGEX ".*[Ee]xample.*\\.(cpp|c|cc|cxx)$")
        list(FILTER sources EXCLUDE REGEX ".*[Mm]ain\\.(cpp|c|cc|cxx)$")
    endif()
    
    # 设置父作用域变量
    set(${VAR_NAME} ${sources} PARENT_SCOPE)
endfunction()

# 函数：设置目标输出目录（统一接口）
# 使用方式: set_target_output_directories(target_name [ARCHIVE dir] [LIBRARY dir] [RUNTIME dir])
function(set_target_output_directories TARGET_NAME)
    set(ARCHIVE_DIR "${CMAKE_BINARY_DIR}/lib")
    set(LIBRARY_DIR "${CMAKE_BINARY_DIR}/lib")
    set(RUNTIME_DIR "${CMAKE_BINARY_DIR}/bin")
    
    # 解析参数
    set(current_option "")
    foreach(arg ${ARGN})
        if(arg STREQUAL "ARCHIVE" OR arg STREQUAL "LIBRARY" OR arg STREQUAL "RUNTIME")
            set(current_option ${arg})
        elseif(current_option)
            if(current_option STREQUAL "ARCHIVE")
                set(ARCHIVE_DIR ${arg})
            elseif(current_option STREQUAL "LIBRARY")
                set(LIBRARY_DIR ${arg})
            elseif(current_option STREQUAL "RUNTIME")
                set(RUNTIME_DIR ${arg})
            endif()
            set(current_option "")
        endif()
    endforeach()
    
    # 设置属性
    set_target_properties(${TARGET_NAME} PROPERTIES
        ARCHIVE_OUTPUT_DIRECTORY "${ARCHIVE_DIR}"
        LIBRARY_OUTPUT_DIRECTORY "${LIBRARY_DIR}"
        RUNTIME_OUTPUT_DIRECTORY "${RUNTIME_DIR}"
    )
endfunction()

# 函数：添加编译定义（统一接口，支持条件）
# 使用方式: add_target_definitions(target_name [CONFIG config] def1 def2 ...)
function(add_target_definitions TARGET_NAME)
    set(definitions "")
    set(config_condition "")
    set(collecting_definitions FALSE)
    
    # 解析参数
    foreach(arg ${ARGN})
        if(arg STREQUAL "CONFIG")
            set(collecting_definitions FALSE)
            set(expecting_config TRUE)
        elseif(expecting_config)
            set(config_condition "$<CONFIG:${arg}>")
            set(expecting_config FALSE)
            set(collecting_definitions TRUE)
        elseif(collecting_definitions OR definitions STREQUAL "")
            list(APPEND definitions ${arg})
            set(collecting_definitions TRUE)
        endif()
    endforeach()
    
    # 添加定义
    if(config_condition)
        target_compile_definitions(${TARGET_NAME} PRIVATE ${config_condition} ${definitions})
    else()
        target_compile_definitions(${TARGET_NAME} PRIVATE ${definitions})
    endif()
endfunction()

# 自动调用设置函数
setup_compile_cache()

